package com.company.arithmetic;

/**
 * Created by v on 17-2-23.
 */
public class TicTacToeAI {
    private int[] board;

    //默认构造方法是个空棋盘
    public TicTacToeAI(){
    }

    //给定棋盘的构造方法
    public TicTacToeAI(int[] board){
        for(int i=0;i<board.length;i++){
            this.board[i]=board[i];
        }
    }

    //输入一个来自玩家的参数,返回一个AI下一步的参数(0-8)
    public int next(int next){
        board[next]=HUMAN;
        return findCompMove().move;
    }

    //电脑下棋和人下棋的标记
    private static final int COMP=1;
    private static final int HUMAN=-1;

    //赢记1,平记0,数记-1
    private static final int COMP_WIN =1;
    private static final int DRAW=0;
    private static final int COMP_LOSE =-1;

    //判断电脑是否下一步就赢了
    private MoveInfo immediateCompWin(){
        return immediateWin(COMP);
    }

    //判断玩家是否下一步就赢了
    private MoveInfo immediateHumanWin(){
        return immediateWin(HUMAN);
    }

    //判断某个对象是否能在下一步赢了
    private MoveInfo immediateWin(int player){
        for(int i=0;i<9;i++){
            if(isEmpty(i)){
                place(i,player);
                if(isWin(player)){
                    unplace(i);
                    return new MoveInfo(i,player);
                }
                unplace(i);
            }
        }
        return null;
    }

    //把棋下载某个位置上
    private void place(int current,int player){
        board[current]=player;
    }

    //把棋从某个位置上撤销
    private void unplace(int current){
        board[current]=0;
    }

    //判断某位玩家是否已经赢了
    private boolean isWin(int player){
        for(int i=0;i<3;i++){
            if(board[i*3]==board[i*3+1]
                    &&board[i*3+1]==board[i*3+2]
                    &&board[i*3+2]==player)
                return true;

            if(board[i]==board[i+3]
                    &&board[i+3]==board[i+6]
                    &&board[i+6]==player)
                return true;
        }

        if(board[0]==board[4]
                &&board[4]==board[8]
                &&board[8]==player)
            return true;

        if(board[2]==board[4]
                &&board[4]==board[6]
                &&board[6]==player)
            return true;

        return false;
    }

    //判断一个位置是否为空(是否已经下在上面)
    private boolean isEmpty(int current){
        if(board[current]==0)
            return true;
        else
            return false;
    }

    //判断棋盘是否已满
    private boolean fullBoard(){
        for(int i=0;i<9;i++){
            if(isEmpty(i)) return false;
        }
        return true;
    }

    /**
     * Recursive method to find best move for computer.
     * MoveInfo.move returns a number from 1-9 indicating square.
     * Possible evaluations satisfy COMP_LOSS<DRAW<COMP_WIN.
     * Complementary method findHumanMove is Figure 10.67.
     */
    private MoveInfo findCompMove(){
        int responseValue;
        int value,bestMove=0;
        MoveInfo quickWinInfo;

        if(fullBoard()){
            value=DRAW;
        }else if((quickWinInfo=immediateCompWin())!=null){
            return quickWinInfo;
        }else {
            value= COMP_LOSE;
            for(int i=0;i<9;i++){
                if(isEmpty(i)){
                    place(i,COMP);
                    responseValue=findHumanMove().value;
                    unplace(i);

                    if(responseValue>value){
                        value=responseValue;
                        bestMove=i;
                    }
                }
            }
        }

        return new MoveInfo(bestMove,value);
    }

    //计算玩家的move
    private MoveInfo findHumanMove(){
        int responseValue;
        int value= COMP_WIN;
        int bestMove=0;

        MoveInfo quickWinInfo;

        if(fullBoard()){
            value=DRAW;
        }else if((quickWinInfo=immediateHumanWin())!=null){
            return quickWinInfo;
        }else {
            for(int i=0;i<9;i++){
                if(isEmpty(i)){
                    place(i,HUMAN);
                    responseValue=findCompMove().value;
                    unplace(i);

                    if(responseValue<value){
                        value=responseValue;
                        bestMove=i;
                    }
                }
            }
        }
        return new MoveInfo(bestMove,value);
    }

    private class MoveInfo {
        public int move;
        public int value;

        public MoveInfo(int m,int v){
            move=m;
            value=v;
        }
    }
}